package com.cdqidi.core.weixinmanager.controller.api;

import com.cdqidi.core.weixinmanager.domain.QrDTO;
import com.cdqidi.core.weixinmanager.domain.WxDTO;
import com.cdqidi.core.weixinmanager.service.wx.WxaApiService;
import com.cdqidi.core.weixinmanager.util.FileUtil;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.exception.ApiException;
import com.jfinal.springboot.weixin.annotation.ApiType;
import com.jfinal.springboot.weixin.annotation.WxApi;
import com.jfinal.weixin.sdk.api.ApiResult;
import com.jfinal.wxaapp.api.WxaMaterialApi;
import com.jfinal.wxaapp.api.WxaUserApi;
import com.qd.common.sys.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * APP_微信小程序接口
 *
 * @author sjk
 */
@RestController
@WxApi(type = ApiType.WXA)
@RequestMapping("/wxmanager/wxaApi/")
@Slf4j
@Validated
public class WxaApiController {
    private static final String PHONE_NUMBER = "phoneNumber";
    private static final String PURE_PHONE_NUMBER = "purePhoneNumber";
    private static final String COUNTRY_CODE = "countryCode";
    private final WxaApiService wxaApiService;

    @Resource
    private WxDTO wxDto;

    @Autowired
    public WxaApiController(WxaApiService wxaApiService) {
        this.wxaApiService = wxaApiService;
    }

    /**
     * 获得openid
     *
     * @param code 小程序前段传入
     * @return openid
     */
    @RequestMapping("/getOpenId")
    public ApiResultWrapper<Object> getOpenId(@Validated @NotBlank(message = "code不能为空") String code) {
        return wxaApiService.getWxaOpenId(code);
    }

    /**
     * 生成葵花码，有次数限制
     * 葵花码永久有效，接口 createQRCode 加上接口 get，总共生成的码数量限制为 100,000，
     * 请谨慎调用。
     *
     * @param qrDto 前端对象
     * @return 图片绝对路径
     */
    @PostMapping(value = "/createQRCode")
    public ApiResultWrapper<Object> createQrCode(@RequestBody @Validated QrDTO qrDto) {
        return wxaApiService.crateQr(qrDto);
    }

    /**
     * 生成葵花码，有次数限制
     * 葵花码永久有效，接口 createQRCode 加上接口 get，总共生成的码数量限制为 100,000，请谨慎调用。
     *
     * @param qrDto 前端对象
     * @return 图片绝对路径
     */
    @PostMapping(value = "/getQrCode")
    public ApiResultWrapper<Object> getQrCode(@RequestBody @Validated QrDTO qrDto) {
        return wxaApiService.getQrCode(qrDto);
    }

    /**
     * 生成葵花码，无次数限制
     * 葵花码永久有效，每分钟五千次。
     *
     * @param qrDto 前端对象
     * @return 图片绝对路径
     */
    @PostMapping(value = "/getUnlimited")
    public ApiResultWrapper<Object> getUnlimited(@RequestBody @Validated QrDTO qrDto) {
        return wxaApiService.getUnlimited(qrDto);
    }

    /**
     * 解密手机号
     *
     * @param jsCode        登录时获取的 code
     * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
     * @param iv            加密算法的初始向量
     * @return {
     * "phoneNumber": "13580006666",
     * "purePhoneNumber": "13580006666",
     * "countryCode": "86",
     * "watermark":
     * {
     * "appid":"APPID",
     * "timestamp": TIMESTAMP
     * }
     * }
     * phoneNumber	String	用户绑定的手机号（国外手机号会有区号）
     * purePhoneNumber	String	没有区号的手机号
     * countryCode	String	区号
     */
    @RequestMapping(value = "/encryptedPhoneNumber")
    public ApiResultWrapper<Map<String, Object>> encryptedPhoneNumber(@NotBlank(message = "jsCode不能为空") String jsCode, @NotBlank(message = "encryptedData不能为空") String encryptedData, @NotBlank(message = "iv不能为空") String iv) {
        ApiResult result = WxaUserApi.getSessionKey(jsCode);
        if (result.isSucceed()) {
            String sessionKey = result.getStr("session_key");
            String openid = result.getStr(Constants.OPENID);
            String unionid = result.getStr("unionid");
            result = WxaUserApi.getUserInfo(sessionKey, encryptedData, iv);
            if (result.isSucceed()) {
                Map<String, Object> map = new HashMap<>(5);
                map.put(PHONE_NUMBER, result.getStr(PHONE_NUMBER));
                map.put(PURE_PHONE_NUMBER, result.getStr(PURE_PHONE_NUMBER));
                map.put(COUNTRY_CODE, result.getStr(COUNTRY_CODE));
                map.put(Constants.OPENID, openid);
                map.put("unionId", unionid);
                return com.cdqidi.dto.ApiResult.success(map);
            }
            return buildError();
        }
        return buildError();
    }

    private ApiResultWrapper<Map<String, Object>> buildError() {
        return com.cdqidi.dto.ApiResult.error("请重新获取");
    }

    /**
     * 根据Code获取手机号
     *
     * @param code 手机号获取凭证
     * @return 手机号
     */
    @RequestMapping(value = "/getUserPhoneNumber")
    public ApiResultWrapper<Map<String, Object>> getUserPhoneNumber(@NotBlank(message = "code不能为空") String code) {
        ApiResult result = WxaUserApi.getUserPhoneNumber(code);
        if (result.isSucceed()) {
            log.info("getUserPhoneNumber,{}", result.getJson());
            Map<?, ?> resultMap = result.getMap("phone_info");
            Map<String, Object> map = new HashMap<>(3);
            map.put(PHONE_NUMBER, resultMap.get(PHONE_NUMBER));
            map.put(PURE_PHONE_NUMBER, resultMap.get(PURE_PHONE_NUMBER));
            map.put(COUNTRY_CODE, resultMap.get(COUNTRY_CODE));
            return com.cdqidi.dto.ApiResult.success(map);
        }
        return buildError();
    }

    /**
     * 解密数据
     *
     * @param sessionKey    登录时获取的 code
     * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
     * @param iv            加密算法的初始向量
     * @return 解密后的数据
     */
    @RequestMapping(value = "/getUserInfo")
    public ApiResultWrapper<Map<String, Object>> getUserInfo(@NotBlank(message = "sessionKey不能为空") String sessionKey, @NotBlank(message = "encryptedData不能为空") String encryptedData, @NotBlank(message = "iv不能为空") String iv) {
        ApiResult result = WxaUserApi.getUserInfo(sessionKey, encryptedData, iv);
        if (result.isSucceed()) {
            return com.cdqidi.dto.ApiResult.success(result.getAttrs());
        }
        return com.cdqidi.dto.ApiResult.error(result.getErrorCode(), result.getErrorMsg());
    }

    /**
     * 上传媒体文件
     *
     * @param file 文件
     * @param type 类型
     * @return 解密后的数据
     */
    @RequestMapping(value = "/uploadMedia")
    public ApiResultWrapper<Map<String, Object>> upload(@RequestParam MultipartFile file, String type) {
        if (!StringUtils.hasLength(type)) {
            type = "image";
        }
        try {
            try (InputStream inputStream = file.getInputStream()) {
                byte[] bfile = FileUtil.readStream(inputStream);
                File f = new File(wxDto.getQrBasePath() + File.separator + file.getOriginalFilename());
                try (FileOutputStream fos = new FileOutputStream(f)) {
                    try (BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                        bos.write(bfile);
                    }
                }
                ApiResult result = WxaMaterialApi.uploadMedia(f, type);
                if (result.isSucceed()) {
                    return com.cdqidi.dto.ApiResult.success(result.getAttrs());
                }
                return com.cdqidi.dto.ApiResult.error(result.getErrorCode(), result.getErrorMsg());
            }
        } catch (Exception e) {
            throw new ApiException(e);
        }
    }
}